//Project 3 - CS 3451 - Labyrinth Lite
//Instructor: Jarek Rossignac
//Author: Tyler Powell
//Date: September 2011

//Display Image on screen
void drawFace() {
  fill(0);
  String name = "Author: Tyler Powell";
  text(name, width - name.length()*6, 15);
  image(myFace, width-myFace.width/2-10,25,myFace.width/2,myFace.height/2);
  noFill();
}

//Information
void addHeader(String info, int headerLine) {
  fill(0);
  text(info, 10, 15*headerLine);
  noFill();
}

void addFooter(String info, int footerLine) {
  fill(0);
  text(info, 10, height - 15*footerLine);
  noFill();
}

boolean debugMode=false;
void debug(int lineNum) { //use for debugging
  String debugLine = "Debug Mode:";
  addHeader(debugLine, lineNum++);
  addHeader("align: " + align, lineNum++);
  addHeader("Velocity: " + currentVelocity.x + "," + currentVelocity.y, lineNum++);
  addHeader("Acceleration: " + acceleration().x + "," + acceleration().y, lineNum++);
  addHeader("Frame Rate: " + frameRate, lineNum++);
  addHeader("Time: " + time, lineNum++);
  if(!threeD){
    for(pt p : labPoints) {
      text("(" + p.x +"," +p.y +")",p.x,p.y);
    }
  }
}

boolean info = true;
void drawInfo() { //main UI guide
  int headerLineNum = 1;
  int footerLineNum = 1;
  String title = "CS3451 - Project 3 - Labyrinth Lite";
  String helpLine = "Left click to add points. Right click to place ball. Hold shift while clicking to produce walls parallel to the x or y axis.";
  String helpLine2 = "Press Backspace to delete the last created point. Press Delete to remove all points. Press UP or DOWN to change the size of the ball.";
  String directions = "Press the space bar to start or restart a game. Press 'e' to enter edit mode. Press 's' and 'l' to save and load games, respectively.";
  String directions2 = "Press '3' to toggle 3D mode on and off. Press 'd' to toggle debug mode. Press 'h' to toggle UI. Press LEFT or RIGHT to change gravity.";
  String directions3 = "Press 'p' to take a picture.";
  String movement = "Tilt the maze by moving the mouse away from the center of the screen. Get the ball to the green gate.";
  addHeader(title,headerLineNum++);
  addFooter(directions3, footerLineNum++);
  addFooter(directions2, footerLineNum++);
  addFooter(directions, footerLineNum++);
  
  
  if(edit) {
    addFooter(helpLine2,footerLineNum++);
    addFooter(helpLine,footerLineNum++);
    addHeader("Edit Mode", headerLineNum++);
  } else {
    if(countDown>0) {
      addHeader("Play Mode", headerLineNum++);
      addHeader("Time Left: " + countDown, headerLineNum++);
      addFooter(movement, footerLineNum++);
    } else {
      countDown = 0;
//      addHeader("Out Of Time!",headerLineNum++);
    }
  }
  
  addHeader("Gravity: " + gravitationalConstant, headerLineNum++);
  
  if(debugMode) {
    debug(headerLineNum);
  }
}

//Lines and Shapes
boolean threeD=false;
boolean edit = true;
int wallThickness = 10;
void drawWalls(boolean threeD) { //draw the walls from point to point
  if(threeD) {
    //TODO: implement 3D walls
    fill(0);
    pushMatrix();
    rotateX(angleOfRotationX);
    rotateY(angleOfRotationY);
    for(int i = 0; i < labPoints.size()-1; i++) {
//      float xDist = labPoints.get(i).x-labPoints.get(i+1).x;
//      float yDist = labPoints.get(i).y-labPoints.get(i+1).y;
      float totalDist = d(labPoints.get(i),labPoints.get(i+1));
      vec v = new vec(labPoints.get(i),labPoints.get(i+1)); 
      vec plane = new vec(labPoints.get(i), new pt(labPoints.get(i).x+1, labPoints.get(i).y));
      float ang = angle(plane,v); //find the angle the wall makes with x-axis
      drawRectPrism(labPoints.get(i).x, labPoints.get(i).y,0,totalDist,wallThickness,wallThickness,ang);
    }
    if(!labPoints.isEmpty()){ //draw the gate in 3d
      float totalDist2 = d(labPoints.get(labPoints.size()-1),labPoints.get(0));
      vec gate = new vec(labPoints.get(labPoints.size()-1),labPoints.get(0));
      vec plane2 = new vec(labPoints.get(labPoints.size()-1), new pt(labPoints.get(labPoints.size()-1).x+1, labPoints.get(labPoints.size()-1).y));
      float ang2= angle(plane2,gate);
      fill(color(0,255,0));
      drawRect(labPoints.get(labPoints.size()-1).x,labPoints.get(labPoints.size()-1).y,0,totalDist2,wallThickness,0,ang2);
      noFill();
      
    }
    for(int i = 0; i < labPoints.size(); i++) { //draw a sphere at each point
      pushMatrix();
      fill(0);
      translate(labPoints.get(i).x-width/2,labPoints.get(i).y-height/2,0);
      sphere(6);
      noFill();
      popMatrix();
    }
    popMatrix();
    noFill();
  } else {
    stroke(0);
    beginShape();
    for(int i = 0; i < labPoints.size(); i++) { //draw the walls in 2d
      vertex(labPoints.get(i).x, labPoints.get(i).y);
    }
    endShape();
    if(labPoints.size() > 0 && edit) { //check to keep index in bounds
      stroke(200);
      beginShape(); //draw line to mouse position
      vertex(labPoints.get(labPoints.size()-1).x,labPoints.get(labPoints.size()-1).y);
      pt p = null;
      if(align) { //draw line from last point to mouse, or aligned point, for previewing the line
        p = alignPoint(mouseX,mouseY,labPoints.get(labPoints.size()-1));
        vertex(p.x,p.y);
      } else {
        p = new pt(mouseX,mouseY);
        vertex(p.x,p.y);
      }
      endShape();
      stroke(color(0,255,0));
      beginShape(); //draw the gate in 2d toward the point for previewing
      vertex(p.x,p.y);
      vertex(labPoints.get(0).x,labPoints.get(0).y);
      endShape();
      
    } else {
      if (!labPoints.isEmpty()){ //draw the gate from the last point to the first
        pt p = labPoints.get(labPoints.size()-1);
        stroke(color(0,255,0));
        beginShape();
        vertex(p.x,p.y);
        vertex(labPoints.get(0).x,labPoints.get(0).y);
        endShape();
      }
    }
    stroke(color(255,0,0));
    fill(color(255,0,0));
    for(int i = 0; i < labPoints.size(); i++) { //draw an ellipse at each point
      ellipse(labPoints.get(i).x, labPoints.get(i).y,5,5);
    }
    if(edit){
      ellipse(mouseX,mouseY,5,5);
    }
    noFill();
    noStroke();
  }
}

void drawRectPrism(float x, float y, float z, float scaleX, float scaleY, float scaleZ, float ang) {
  pushMatrix();
  translate(x-width/2,y-height/2,z);
  translate(scaleX/2*cos(ang),scaleX/2*sin(ang),0);
  rotateZ(ang);
  scale(scaleX,scaleY,scaleZ);
  box(1);
  popMatrix();
}

void drawRect(float x, float y, float z, float scaleX, float scaleY, float scaleZ, float ang) {
    pushMatrix();
  translate(x-width/2,y-height/2);
  //translate(scaleX/2*cos(ang),scaleX/2*sin(ang));
  rotateZ(ang);
  scale(scaleX,scaleY);
  rect(0,0,1,1);
  popMatrix();
}

void vertex(pt p){
  vertex(p.x,p.y);
}

void line(pt a, pt b){
  stroke(0);
  beginShape();
  vertex(a);
  vertex(b);
  endShape();
  noStroke();
}

